# @Filename:    array
# @Author:      王佳伟
# @Time:        2025-04-01 16:05
# @Describe:    数组操作
import numpy as np

# # numpy.reshape 这个函数在不改变数据的条件下修改形状
# # numpy.reshape(arr, newshape, order')
# # arr：要修改形状的数组
# # newshape：整数或者整数数组，新的形状应当兼容原有形状
# # order：'C'为 C 风格顺序，'F'为 F 风格顺序，'A'为保留原顺序。
#
a = np.arange(8)
print('原始数组：')
print(a)
print('\n')
#
# b = a.reshape(4, 2)
# print('修改后的数组：')
# print(b)
#
# print("=====================")
#
# # numpy.ndarray.flat
# # 该函数返回数组上的一维迭代器，行为类似 Python 内建的迭代器。
# a = np.arange(8).reshape(2, 4)
# print('原始数组：')
# print(a)
# print('\n')
#
# print('调用flat函数之后：')
# # 返回展开数组中的下标的对应元素
# print(a.flat[5])
#
# print("=====================")
#
# # numpy.ndarray.flatten
# # 该函数返回折叠为一维的数组副本，函数接受下列参数：
# # ndarray.flatten(order)
# # order：'C' -- 按行，'F' -- 按列，'A' -- 原顺序，'k' -- 元素在内存中的出现顺序。
# a = np.arange(8).reshape(2, 4)
# print('原始数组：')
# print(a)
# print('\n')
#
# print('展开的数组：')
# print(a.flatten())
# print('\n')
#
# print('以F风格顺序展开的数组：')
# print(a.flatten(order = 'F'))
#
# print("=====================")
#
# # numpy.ravel
# # 这个函数返回展开的一维数组，并且按需生成副本。返回的数组和输入数组拥有相同数据类型。这个函数接受两个参数。
# # numpy.ravel(a, order)
# # order：'C' -- 按行，'F' -- 按列，'A' -- 原顺序，'k' -- 元素在内存中的出现顺序。
#
# a = np.arange(8).reshape(2, 4)
# print('原始数组：')
# print(a)
# print('\n')
#
# print('调用 ravel 函数之后：')
# print(a.ravel())
# print('\n')
#
# print('以F风格顺序调用ravel函数之后：')
# print(a.ravel(order = 'F'))
#
# print("=====================")
#
# # 翻转数组
#
# # numpy.transpose
# # 这个函数翻转给定数组的维度。如果可能的话它会返回一个视图。函数接受下列参数：
# # numpy.transpose(arr, axes)
# # arr：要转置的数组
# # axes：整数的列表，对应维度，通常所有维度都会翻转。
#
# a = np.arange(12).reshape(3, 4)
# print('原数组：')
# print(a)
# print('\n')
#
# print('转置数组：')
# print(np.transpose(a))
#
# print("=====================")
# # numpy.ndarray.T
# # 该函数属于ndarray类，行为类似于numpy.transpose。
#
# a = np.arange(12).reshape(3, 4)
# print('原数组：')
# print(a)
# print('\n')
#
# print('转置数组：')
# print(a.T)
#
# print("=====================")
#
# # numpy.rollaxis
# # 该函数向后滚动特定的轴，直到一个特定位置。这个函数接受三个参数：
# # numpy.rollaxis(arr, axis, start)
# # arr：输入数组
# # axis：要向后滚动的轴，其它轴的相对位置不会改变
# # start：默认为零，表示完整的滚动。会滚动到特定位置。
#
# a = np.arange(8).reshape(2, 2, 2)
# print('原数组：')
# print(a)
# print('\n')
#
# # 将轴2滚动到轴0（宽度到深度）
# print('调用 rollaxis 函数：')
# print(np.rollaxis(a, 2))
# # 将轴0滚动到轴1：（宽度到高度）
# print('\n')
# print('调用 rollaxis 函数：')
# print(np.rollaxis(a, 2, 1))
#
# print("=====================")
#
# # numpy.swapaxes
# # 该函数交换数组的两个轴。
# # 对于 1.10 之前的 NumPy 版本，会返回交换后数组的试图。这个函数接受下列参数：
# # numpy.swapaxes(arr, axis1, axis2)
# # arr：要交换其轴的输入数组
# # axis1：对应第一个轴的整数
# # axis2：对应第二个轴的整数
# a = np.arange(8).reshape(2, 2, 2)
# print('原数组：')
# print(a)
# print('\n')
#
# # 现在交换轴 0（深度方向）到轴 2（宽度方向）
# print('调用swapaxes函数后的数组：')
# print(np.swapaxes(a, 2, 0))

# 修改维度
# broadcast
# 此功能模仿广播机制。 它返回一个对象，该对象封装了将一个数组广播到另一个数组的结果。

# x = np.array([[1], [2], [3]])
# y = np.array([4, 5, 6])
#
# # 对y广播x
# b = np.broadcast(x, y)
# # 它拥有iterator属性，基于自身组件的迭代器元组
# print('对y广播x：')
# r,c = b.iters
# print(next(r),next(c))
# print(next(r),next(c))
# print('\n')
#
# # shape属性返回广播对象的形状
# print('广播对象的形状：')
# print(b.shape)
# print('\n')
#
# # 手动使用broadcast将x与y相加：
# b = np.broadcast(x, y)
# c = np.empty(b.shape)
# print('手动使用 broadcast 将 x 与 y 相加：')
# print(c.shape)
# print('\n')
# c.flat = [u + v for (u, v) in b]
# print('调用flat函数：')
# print(c)
# print('\n')
#
# # 获得了和Numpy内建的广播支持相同的结果
# print('x 与 y的和：')
# print(x + y)
#
# print("=====================")
#
# # numpy.broadcast_to
# # 此函数将数组广播到新形状。 它在原始数组上返回只读视图。
# # 它通常不连续。 如果新形状不符合 NumPy 的广播规则，该函数可能会抛出ValueError。
# # numpy.broadcast_to(array, shape, subok)
# a = np.arange(4).reshape(1, 4)
# print('原数组：')
# print(a)
# print('\n')
#
# print('调用broadcast_to函数之后：')
# print(np.broadcast_to(a, (4, 4)))
#
# print("=====================")
# # numpy.expand_dims
# # 函数通过在指定位置插入新的轴来扩展数组形状。该函数需要两个参数：
# # numpy.expand_dims(arr, axis)
# # arr：输入数组
# # axis：新轴插入的位置
# x = np.array(([1,2],[3,4]))
# print('数组x：')
# print(x)
# print('\n')
#
# y = np.expand_dims(x, axis = 0)
# print('数组y：')
# print(y)
# print('\n')
#
# print('数组 x 和 y的形状：', x.shape, y.shape)
# print('\n')
# # 在位置 1 插入轴
# y = np.expand_dims(x, axis = 1)
#
# print('在位置1插入轴之后的数组y：')
# print(y)
# print('\n')
#
# print('x.ndim 和 y.ndim：', x.ndim, y.ndim)
# print('\n')
#
# print('数组 x 和 y的形状：')
# print('数组 x 和 y的形状：', x.shape, y.shape)
#
# print("=====================")
#
# # numpy.squeeze
# # 函数从给定数组的形状中删除一维条目。 此函数需要两个参数。
# # numpy.squeeze(arr, axis)
# # arr：输入数组
# # axis：整数或整数元组，用于选择形状中单一维度条目的子集
# x = np.arange(9).reshape(1, 3, 3)
# print('数组x：')
# print(x)
# print('\n')
# y = np.squeeze(x)
#
# print('数组y：')
# print(y)
# print('\n')
# print('数组 x 和 y的形状：', x.shape, y.shape)

# 数组的连接
# numpy.concatenate
# 数组的连接是指连接。
# 此函数用于沿指定轴连接相同形状的两个或多个数组。 该函数接受以下参数。
# numpy.concatenate((a1, a2, ...), axis)
# a1, a2, ...：相同类型的数组序列
# axis：沿着它连接数组的轴，默认为 0
# a = np.array([[1, 2], [3, 4]])
# print('第一个数组：')
# print(a)
# print('\n')
# b = np.array([[5, 6], [7, 8]])
# print('第二个数组：')
# print(b)
# print('\n')
# # 两个数组的维度相同
# print('沿轴0连接两个数组：')
# print(np.concatenate((a, b)))
# print('\n')
# print('沿轴1连接两个数组：')
# print(np.concatenate((a, b), axis = 1))
#
# print("=====================")
#
# # numpy.stack
# # 此函数沿新轴连接数组序列。 此功能添加自 NumPy 版本 1.10.0。 需要提供以下参数。
# # numpy.stack(arrays, axis)
# # arrays：相同形状的数组序列
# # axis：返回数组中的轴，输入数组沿着它来堆叠
#
# a = np.array([[1, 2], [3, 4]])
# print('第一个数组：')
# print(a)
# print('\n')
# b = np.array([[5, 6], [7, 8]])
# print('第二个数组：')
# print(b)
# print('\n')
#
# print('沿轴0堆叠两个数组：')
# print(np.stack((a, b), 0))
# print('\n')
#
# print('沿轴1堆叠两个数组：')
# print(np.stack((a, b), 1))
#
# print("=====================")
#
# # numpy.hstack
# # numpy.stack函数的变体，通过堆叠来生成水平的单个数组。
# a = np.array([[1, 2], [3, 4]])
# print('第一个数组：')
# print(a)
# print('\n')
# b = np.array([[5, 6], [7, 8]])
# print('第二个数组：')
# print(b)
# print('\n')
#
# print('水平堆叠：')
# c = np.hstack((a, b))
# print(c)
# print('\n')
#
# print("=====================")
# # numpy.vstack
# # numpy.stack函数的变体，通过堆叠来生成竖直的单个数组。
# a = np.array([[1, 2], [3, 4]])
# print('第一个数组：')
# print(a)
# print('\n')
# b = np.array([[5, 6], [7, 8]])
# print('第二个数组：')
# print(b)
# print('\n')
#
# print('竖直堆叠：')
# c = np.vstack((a, b))
# print(c)
# print('\n')


# 数组分割
# numpy.split
# 该函数沿特定的轴将数组分割为子数组。函数接受三个参数：
# numpy.split(ary, indices_or_sections, axis)
# ary：被分割的输入数组
# indices_or_sections：可以是整数，表明要从输入数组创建的，等大小的子数组的数量。 如果此参数是一维数组，则其元素表明要创建新子数组的点。
# axis：默认为 0
# a = np.arange(9)
# print('第一个数组：')
# print(a)
# print('\n')
#
# print('将数组分为三个大小相等的子数组：')
# b = np.split(a, 3)
# print(b)
# print('\n')
#
# print('将数组在一维数组中表明的位置分割：')
# b = np.split(a, [4, 7])
# print(b)
#
# print("=====================")
#
# # numpy.hsplit
# # numpy.hsplit是split()函数的特例，其中轴为 1 表示水平分割，无论输入数组的维度是什么。
# a = np.arange(16).reshape(4,4)
# print('第一个数组：')
# print(a)
# print('\n')
#
# print('水平分割：')
# b = np.hsplit(a, 2)
# print(b)
# print('\n')
#
# print("=====================")
# a = np.arange(16).reshape(4,4)
# print('第一个数组：')
# print(a)
# print('\n')
#
# print('竖直分割：')
# b = np.vsplit(a, 2)
# print(b)

# 添加/删除元素
# numpy.resize
# 此函数返回指定大小的新数组。 如果新大小大于原始大小，则包含原始数组中的元素的重复副本。 该函数接受以下参数。
# numpy.resize(arr, shape)
# arr：要修改大小的输入数组
# shape：返回数组的新形状

a = np.array([[1, 2, 3], [4, 5, 6]])

print('第一个数组：')
print(a)
print('\n')

print('第一个数组的形状：')
print(a.shape)
print('\n')
b = np.resize(a, (3, 2))

print('第二个数组：')
print(b)
print('\n')

print('第二个数组的形状：')
print(b.shape)
print('\n')

# 要注意a的第一行在b中重复出现，因为尺寸变大了
print('修改第二个数组的大小：')
b = np.resize(a, (3, 3))
print(b)

print("=====================")

# numpy.append
# 此函数在输入数组的末尾添加值。 附加操作不是原地的，而是分配新的数组。
# 此外，输入数组的维度必须匹配否则将生成ValueError。
# numpy.append(arr, values, axis)
# arr：输入数组
# values：要向arr添加的值，比如和arr形状相同（除了要添加的轴）
# axis：沿着它完成操作的轴。如果没有提供，两个参数都会被展开。

a = np.array([[1, 2, 3], [4, 5, 6]])

print('第一个数组：')
print(a)
print('\n')

print('向数组添加元素：')
print(np.append(a, [7, 8, 9]))
print('\n')

print('沿轴0添加元素')
print(np.append(a, [[7, 8, 9]], axis = 0))
print('\n')

print('沿轴1添加元素')
print(np.append(a, [[5, 5, 5], [7, 8, 9]], axis = 1))

print("=====================")

# numpy.insert
# 此函数在给定索引之前，沿给定轴在输入数组中插入值。
# 如果值的类型转换为要插入，则它与输入数组不同。
# 插入没有原地的，函数会返回一个新数组。 此外，如果未提供轴，则输入数组会被展开。

# numpy.insert(arr, obj, values, axis)
# arr：输入数组
# obj：在其之前插入值的索引
# values：要插入的值
# axis：沿着它插入的轴，如果未提供，则输入数组会被展开
a = np.array([[1, 2], [3, 4], [5, 6]])
print('第一个数组：')
print(a)
print('\n')

print('未传递Axis参数，在插入之前输入数组会被展开')
print(np.insert(a, 3, [11, 12]))
print('\n')
print('传递了Axis参数，会广播值数组来配输入数组。')

print('沿轴0广播：')
print(np.insert(a, 1, [11], axis = 0))
print('\n')

print('沿轴1广播：')
print(np.insert(a, 1, 11, axis = 1))

print("=====================")

# numpy.delete
# 此函数返回从输入数组中删除指定子数组的新数组。
# 与insert()函数的情况一样，如果未提供轴参数，则输入数组将展开。 该函数接受以下参数：
# Numpy.delete(arr, obj, axis)
# arr：输入数组
# obj：可以被切片，整数或者整数数组，表明要从输入数组删除的子数组
# axis：沿着它删除给定子数组的轴，如果未提供，则输入数组会被展开

a = np.arange(12).reshape(3, 4)
print('第一个数组：')
print(a)
print('\n')

print('未传递Axis参数，在插入之前输入数组会被展开')
print(np.delete(a, 5))
print('\n')

print('删除第二列：')
print(np.delete(a, 1, axis = 1))
print('\n')

print('包含从数组中删除的替代值的切片：')
a = np.array([1,2,3,4,5,6,7,8,9,10])
print(np.delete(a, np.s_[::2]))

print("=====================")
# numpy.unique
# 此函数返回输入数组中的去重元素数组。
# 该函数能够返回一个元组，包含去重数组和相关索引的数组。
# 索引的性质取决于函数调用中返回参数的类型。

# numpy.unique(arr, return_index, return_inverse, return_counts)
# arr：输入数组，如果不是一维数组则会展开
# return_index：如果为true，返回输入数组中的元素下标
# return_inverse：如果为true，返回去重数组的下标，它可以用于重构输入数组
# return_counts：如果为true，返回去重数组中的元素在原数组中的出现次数

a = np.array([5,2,6,2,7,5,6,8,2,9])
print('第一个数组：')
print(a)
print('\n')

print('第一个数组的去重值：')
u = np.unique(a)
print(u)
print('\n')

print('去重数组的索引数组：')
u, indices = np.unique(a, return_index = True)
print(indices)
print('\n')

print('我们可以看到每个和原数组下标对应的数值：')
print(a)
print('\n')

print('去重数组的下标：')
u, indices = np.unique(a, return_inverse = True)
print(u)
print('\n')

print('下标为：')
print(indices)
print('\n')

print('使用下标重构原数组：')
print(u[indices])
print('\n')

print('返回去重元素的重复数量：')
u, indices = np.unique(a, return_counts = True)
print(u)
print(indices)






